using System;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;

using Crainiate.Data.Persistence.Cache;

namespace Crainiate.Data.Persistence
{
    [Serializable]
    public class Columns: Collection<IColumn>, IColumns, ISerializable, IDeserializationCallback
    {
        //Working variables
        private SerializationInfo _info;
        private int _cache;

        //Constructors
        public Columns()
        {

        }

        public Columns(Type type, string[] fields)
        {
            foreach (String field in fields)
            {
                Add(new Column(type.GetProperty(field)));
            }
        }

        public Columns(PropertyInfo[] properties)
        {
            foreach (PropertyInfo prop in properties)
            {
                Add(new Column(prop));
            }
        }

        protected Columns(SerializationInfo info, StreamingContext context)
        {
            _info = info;
        }

        //Methods
        public IColumn[] ToArray()
        {
            IColumn[] destinationArray = new IColumn[Count];
            this.CopyTo(destinationArray, 0);
            return destinationArray;
        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Fields", ToArray());
        }

        public virtual void OnDeserialization(object sender)
        {
            IColumn[] array = (IColumn[]) _info.GetValue("Fields", typeof(IColumn[]));

            Clear();
            foreach (IColumn field in array)
            {
                Add(field);
            }

            _info = null;
            _cache = 0;
        }

        //Overrides
        protected override void ClearItems()
        {
            _cache = 0;
            base.ClearItems();
        }

        protected override void InsertItem(int index, IColumn item)
        {
            _cache = 0;
            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            _cache = 0;
            base.RemoveItem(index);
        }
            
        public sealed override int GetHashCode()
        {   
            //Return from cache if available
            if (_cache != 0) return _cache;

            StringBuilder builder = new StringBuilder();

            //Use the property info from each field rather than the hash for speed
            foreach (IColumn field in this)
            {
                PropertyInfo prop = field.PropertyInfo;
                
                if (typeof(IView).IsAssignableFrom(prop.ReflectedType))
                {
                    ReflectionCacheItem cache = Component.Instance.ReflectionCache.Lookup(prop.ReflectedType);
                    prop = cache.GetOriginalProperty(prop);
                }

                builder.Append(prop.ToString());
            }

            _cache = builder.ToString().GetHashCode();
            return _cache;
        }
    }
}